package com.freak.kotlinfitnessserver.activity

import android.bluetooth.BluetoothAdapter
import android.bluetooth.BluetoothDevice
import android.bluetooth.BluetoothGatt
import android.bluetooth.BluetoothGattCharacteristic
import android.bluetooth.BluetoothGattDescriptor
import android.bluetooth.BluetoothGattServer
import android.bluetooth.BluetoothGattServerCallback
import android.bluetooth.BluetoothGattService
import android.bluetooth.BluetoothManager
import android.bluetooth.BluetoothProfile
import android.bluetooth.le.AdvertiseCallback
import android.bluetooth.le.AdvertiseData
import android.bluetooth.le.AdvertiseSettings
import android.bluetooth.le.BluetoothLeAdvertiser
import android.content.Intent
import android.content.pm.PackageManager
import android.os.Bundle
import android.os.Handler
import android.os.HandlerThread
import android.os.Looper
import android.os.Message
import android.os.ParcelUuid
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope
import com.freak.kotlinfitnessserver.activity.fragment.viewmodel.DeviceInfoViewModel
import com.freak.kotlinfitnessserver.activity.fragment.viewmodel.FeaturesViewModel
import com.freak.kotlinfitnessserver.activity.fragment.viewmodel.SportViewModel
import com.freak.kotlinfitnessserver.activity.fragment.viewmodel.SupportRangeViewModel
import com.freak.kotlinfitnessserver.app.App
import com.freak.kotlinfitnessserver.constant.ByteConstant
import com.freak.kotlinfitnessserver.constant.DeviceConstant
import com.freak.kotlinfitnessserver.constant.fitness.DisProtocolConstant
import com.freak.kotlinfitnessserver.constant.fitness.FitnessControlConstant
import com.freak.kotlinfitnessserver.constant.fitness.FitnessExtendedProtocolConstant
import com.freak.kotlinfitnessserver.constant.fitness.FitnessMachineStatusConstant
import com.freak.kotlinfitnessserver.constant.fitness.FitnessProtocolConstant
import com.freak.kotlinfitnessserver.data.FitnessConfigData
import com.freak.kotlinfitnessserver.data.SportStatusData
import com.freak.kotlinfitnessserver.databinding.ActivityBleServerBinding
import com.freak.kotlinfitnessserver.factory.GattParses
import com.freak.kotlinfitnessserver.factory.INotifyFactory
import com.freak.kotlinfitnessserver.factory.NotifyFactory
import com.freak.kotlinfitnessserver.factory.ResponseFactory
import com.freak.kotlinfitnessserver.queue.BlueMessageQueue
import com.freak.kotlinfitnessserver.queue.IBlueMessageQueueListen
import com.freak.kotlinfitnessserver.util.ByteUtil
import com.freak.kotlinfitnessserver.util.LogUtil
import com.freak.kotlinfitnessserver.util.ToastUtil
import kotlinx.coroutines.launch
import java.util.LinkedList

class BleServerActivity : AppCompatActivity() {
    companion object {
        const val TAG: String = "BleServerActivity"

        const val DEVICE: String = "Device"

        const val ADD_SERVICE: Int = 1

        const val SEND_REAL_TIME_DATA = 2
    }

    private lateinit var binding: ActivityBleServerBinding

    private lateinit var deviceType: String

    private var mBluetoothAdapter: BluetoothAdapter? = null

    private var mBluetoothManager: BluetoothManager? = null

    private var mBluetoothLeAdvertiser: BluetoothLeAdvertiser? = null

    private lateinit var mServer: BluetoothGattServer

    private lateinit var mDisService: BluetoothGattService

    private lateinit var mSystemIDCharacteristic: BluetoothGattCharacteristic

    private lateinit var mModelNumberCharacteristic: BluetoothGattCharacteristic

    private lateinit var mSerialNumberCharacteristic: BluetoothGattCharacteristic

    private lateinit var mFirmwareRevisionCharacteristic: BluetoothGattCharacteristic

    private lateinit var mHardwareRevisionCharacteristic: BluetoothGattCharacteristic

    private lateinit var mSoftwareRevisionCharacteristic: BluetoothGattCharacteristic

    private lateinit var mManufacturerNameCharacteristic: BluetoothGattCharacteristic

    private lateinit var mFitnessService: BluetoothGattService

    private lateinit var mFitnessMachineFeatureCharacteristic: BluetoothGattCharacteristic

    private lateinit var mTreadmillDataCharacteristic: BluetoothGattCharacteristic

    private lateinit var mCrossTrainerDataCharacteristic: BluetoothGattCharacteristic

    private lateinit var mRowerDataCharacteristic: BluetoothGattCharacteristic

    private lateinit var mIndoorBikeDataCharacteristic: BluetoothGattCharacteristic

    private lateinit var mTrainingStatusCharacteristic: BluetoothGattCharacteristic

    private lateinit var mSupportedSpeedRangeCharacteristic: BluetoothGattCharacteristic

    private lateinit var mSupportedInclinationRangeCharacteristic: BluetoothGattCharacteristic

    private lateinit var mSupportedResistanceLevelRangeCharacteristic: BluetoothGattCharacteristic

    private lateinit var mSupportedHeartRateRangeCharacteristic: BluetoothGattCharacteristic

    private lateinit var mSupportedPowerRangeCharacteristic: BluetoothGattCharacteristic

    private lateinit var mFitnessMachineControlPointCharacteristic: BluetoothGattCharacteristic

    private lateinit var mFitnessMachineStatusCharacteristic: BluetoothGattCharacteristic

    private lateinit var mFitnessExtendedCharacteristic: BluetoothGattCharacteristic

    private lateinit var mResponseFactory: ResponseFactory

    private lateinit var mLinkedList: LinkedList<BluetoothGattService>

    private lateinit var mHandlerThread: HandlerThread

    private lateinit var mBlueMessageQueueHandler: BlueMessageQueueHandler

    private lateinit var mGattParses: GattParses

    private lateinit var mNotifyFactory: NotifyFactory

    private lateinit var mSportStatusData: SportStatusData

    private lateinit var mBlueMessageQueue: BlueMessageQueue

    private val deviceInfoViewModel: DeviceInfoViewModel by viewModels {
        DeviceInfoViewModel.DeviceInfoViewModelFactory((this.application as App).fitnessDeviceDatabase.deviceInfoDataDao())
    }

    private val supportRangeViewModel: SupportRangeViewModel by viewModels {
        SupportRangeViewModel.SupportRangeViewModelFactory((this.application as App).fitnessDeviceDatabase.supportRangeDataDao())
    }

    private val featuresViewModel: FeaturesViewModel by viewModels {
        FeaturesViewModel.FeaturesViewModelFactory((this.application as App).fitnessDeviceDatabase.featuresDataDao())
    }

    private val sportViewModel: SportViewModel by viewModels()

    private inner class BlueMessageQueueHandler(looper: Looper) : Handler(looper) {
        override fun handleMessage(msg: Message) {
            super.handleMessage(msg)
            when (msg.what) {
                ADD_SERVICE -> {
                    val bluetoothGattService = mLinkedList.pollFirst()
                    if (bluetoothGattService == null) {
                        displayInfo("获取服务异常")
                        return
                    }
                    displayInfo("开始添加服务 : ${bluetoothGattService.uuid}")
                    mServer.addService(bluetoothGattService)
                }

                SEND_REAL_TIME_DATA -> {
                    LogUtil.i(TAG, "SEND_REAL_TIME_DATA")
                    val bundle = msg.data
                    bundle ?: let {
                        LogUtil.i(TAG, "bundle is null")
                        return
                    }
                    val device = bundle.getParcelable<BluetoothDevice>(DEVICE)
                    device ?: let {
                        LogUtil.i(TAG, "device is null")
                        return
                    }
                    looperSendRealTimeData(device)
                }
            }
        }
    }

    private val mBlueMessageQueueCallback = object : IBlueMessageQueueListen {
        override fun onNotifyNewMessage(
            byteArray: ByteArray,
            device: BluetoothDevice,
            characteristic: BluetoothGattCharacteristic
        ) {
            notifyMessage(device, characteristic, byteArray)
        }

    }

    private val mAdvertiseCallback = object : AdvertiseCallback() {
        override fun onStartFailure(errorCode: Int) {
            super.onStartFailure(errorCode)
            LogUtil.i(TAG, "onStartFailure errorCode = $errorCode")
            if (errorCode == ADVERTISE_FAILED_DATA_TOO_LARGE) {
                displayInfo("启动Ble广播失败 数据报文超出31字节")
            } else {
                displayInfo("启动Ble广播失败 errorCode = $errorCode")
            }
        }

        override fun onStartSuccess(settingsInEffect: AdvertiseSettings?) {
            super.onStartSuccess(settingsInEffect)
            LogUtil.i(TAG, "onStartSuccess")
            displayInfo("启动Ble广播成功, 可连接, 持续广播")
        }
    }

    private val mBluetoothGattServerCallback = object : BluetoothGattServerCallback() {

        override fun onConnectionStateChange(device: BluetoothDevice?, status: Int, newState: Int) {
            super.onConnectionStateChange(device, status, newState)
            LogUtil.i(
                TAG,
                "onConnectionStateChange Server status = $status  newState = $newState\""
            )
            if (status == BluetoothGatt.GATT_SUCCESS) {
                //连接成功
                if (newState == BluetoothProfile.STATE_CONNECTED) {
                    displayInfo("${device?.address} 连接成功")
                } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
                    displayInfo("${device?.address} 断开连接")
                }
            } else {
                displayInfo("onConnectionStateChange status = $status newState = $newState")
            }
        }

        override fun onServiceAdded(status: Int, service: BluetoothGattService?) {
            super.onServiceAdded(status, service)
            LogUtil.i(TAG, "onServiceAdded status = $status service = ${service?.uuid}")
            if (status == BluetoothGatt.GATT_SUCCESS) {
                displayInfo("添加Gatt服务成功 UUUID = ${service?.uuid}")
                if (!mLinkedList.isEmpty()) {
                    mBlueMessageQueueHandler.sendEmptyMessage(ADD_SERVICE)
                }
            } else {
                displayInfo("添加Gatt服务失败")
            }
        }

        override fun onCharacteristicReadRequest(
            device: BluetoothDevice?,
            requestId: Int,
            offset: Int,
            characteristic: BluetoothGattCharacteristic?
        ) {
            super.onCharacteristicReadRequest(device, requestId, offset, characteristic)
            LogUtil.i(
                TAG,
                "onCharacteristicReadRequest device = ${device?.toString()} characteristic = ${characteristic?.uuid} " +
                        "offset = $offset requestId = $requestId"
            )
            displayInfo(
                "${device?.address} 请求读取特征值:  UUID = ${characteristic?.uuid} " +
                        "读取值 = ${characteristic?.value?.let { ByteUtil.bytesToHexString(it) }} offset = $offset requestId = $requestId"
            )
            // offset不等于0，不回复消息
            if (offset == 0) {
                LogUtil.i(TAG, "开始回复消息")
                // 响应客户端
                val responseByteArray = mResponseFactory.createFactory(deviceType)
                    ?.handleCharacteristicReadRequest(
                        device,
                        requestId,
                        offset,
                        characteristic,
                        sportViewModel.fitnessConfigData
                    )
                displayInfo("回应的数据 = ${responseByteArray?.let { ByteUtil.bytesToHexString(it) }}")
                if (responseByteArray == null || responseByteArray.isEmpty()) {
                    LogUtil.e(TAG, "error responseByteArray")
                    displayInfo("回复消息异常")
                    return
                }
                sendRespondWithReadOrWrite(
                    device,
                    requestId,
                    BluetoothGatt.GATT_SUCCESS,
                    offset,
                    responseByteArray
                )
                displayInfo(
                    "${device?.address} 回复读取特征值:  UUID = ${characteristic?.uuid} " +
                            "回复值 = ${ByteUtil.bytesToHexString(responseByteArray)}"
                )
                LogUtil.i(TAG, "回复消息结束")
            } else {
                displayInfo(
                    "错误offset $offset"
                )
                sendRespondWithReadOrWrite(
                    device,
                    requestId,
                    BluetoothGatt.GATT_SUCCESS,
                    offset,
                    characteristic?.value
                )
            }
        }

        override fun onCharacteristicWriteRequest(
            device: BluetoothDevice?,
            requestId: Int,
            characteristic: BluetoothGattCharacteristic?,
            preparedWrite: Boolean,
            responseNeeded: Boolean,
            offset: Int,
            value: ByteArray?
        ) {
            super.onCharacteristicWriteRequest(
                device,
                requestId,
                characteristic,
                preparedWrite,
                responseNeeded,
                offset,
                value
            )
            LogUtil.i(
                TAG, "onCharacteristicWriteRequest " +
                        "requestId = $requestId " +
                        "preparedWrite = $preparedWrite " +
                        "responseNeeded = $responseNeeded " +
                        "offset = $offset " +
                        "value = ${value?.let { ByteUtil.bytesToHexString(it) }}"
            )
            //刷新该特征值
            characteristic?.value = value
            // 响应客户端
            sendRespondWithReadOrWrite(
                device, requestId, BluetoothGatt.GATT_SUCCESS,
                offset, value
            )
            displayInfo(
                "${device?.address} 请求写入特征值:  UUID = ${characteristic?.uuid} " +
                        "写入值 = ${value?.let { ByteUtil.bytesToHexString(it) }} " +
                        "requestId = $requestId " +
                        "preparedWrite = $preparedWrite " +
                        "responseNeeded = $responseNeeded " +
                        "offset = $offset"
            )
            val uuid = characteristic?.uuid
            uuid ?: let {
                LogUtil.i(TAG, "uuid is null")
                return
            }
            value ?: let {
                LogUtil.i(TAG, "value is null")
                return
            }
            when (uuid) {
                FitnessProtocolConstant.FitnessMachineControlPoint -> {
                    handleControlPoint(value, device, characteristic)
                }

                FitnessExtendedProtocolConstant.fitnessExtended -> {
                    // 扩展特征值，只做接收
                    handleFitnessExtendedData(value)
                }

                else -> {
                    LogUtil.i(TAG, "other uuid")
                }
            }
        }

        override fun onDescriptorWriteRequest(
            device: BluetoothDevice?,
            requestId: Int,
            descriptor: BluetoothGattDescriptor?,
            preparedWrite: Boolean,
            responseNeeded: Boolean,
            offset: Int,
            value: ByteArray?
        ) {
            super.onDescriptorWriteRequest(
                device,
                requestId,
                descriptor,
                preparedWrite,
                responseNeeded,
                offset,
                value
            )
            LogUtil.i(
                TAG,
                "onDescriptorWriteRequest value = ${value?.let { ByteUtil.bytesToHexString(it) }} " +
                        " requestId = $requestId responseNeeded = $responseNeeded"
            )
            //刷新描述值
            descriptor?.value = value
            displayInfo(
                "${device?.address} 请求写入描述值:  UUID = ${descriptor?.uuid} " +
                        "写入值 = ${descriptor?.value?.let { ByteUtil.bytesToHexString(it) }}"
            )
            // 响应客户端
            sendRespondWithReadOrWrite(
                device, requestId, BluetoothGatt.GATT_SUCCESS,
                offset, value
            )
        }

        override fun onDescriptorReadRequest(
            device: BluetoothDevice?,
            requestId: Int,
            offset: Int,
            descriptor: BluetoothGattDescriptor?
        ) {
            super.onDescriptorReadRequest(device, requestId, offset, descriptor)
            LogUtil.i(TAG, "onDescriptorReadRequest")
            // 响应客户端
            sendRespondWithReadOrWrite(
                device, requestId, BluetoothGatt.GATT_SUCCESS,
                offset, descriptor?.value
            )
            displayInfo(
                "${device?.address} 请求读取描述值:  UUID = ${descriptor?.uuid} " +
                        "读取值 = ${descriptor?.value?.let { ByteUtil.bytesToHexString(it) }}"
            )
        }

        override fun onExecuteWrite(device: BluetoothDevice?, requestId: Int, execute: Boolean) {
            super.onExecuteWrite(device, requestId, execute)
            LogUtil.i(TAG, "onExecuteWrite")
        }

        override fun onMtuChanged(device: BluetoothDevice?, mtu: Int) {
            super.onMtuChanged(device, mtu)
            LogUtil.i(TAG, "onMtuChanged")
        }

        override fun onNotificationSent(device: BluetoothDevice?, status: Int) {
            super.onNotificationSent(device, status)
            // 调用notifyCharacteristicChanged时，必须等回到到此处才可以进行下一个notify消息发送
            LogUtil.i(TAG, "onNotificationSent")
            if (status == BluetoothGatt.GATT_SUCCESS) {
                displayInfo("${device?.address} 通知发送成功")
            } else {
                displayInfo("${device?.address} 通知发送失败 status = $status")
            }
            // 触发新消息发送
            mBlueMessageQueue.immediateTriggerNewMessage()
        }

        override fun onPhyRead(device: BluetoothDevice?, txPhy: Int, rxPhy: Int, status: Int) {
            super.onPhyRead(device, txPhy, rxPhy, status)
            LogUtil.i(TAG, "onPhyRead")
        }

        override fun onPhyUpdate(device: BluetoothDevice?, txPhy: Int, rxPhy: Int, status: Int) {
            super.onPhyUpdate(device, txPhy, rxPhy, status)
            LogUtil.i(TAG, "onPhyUpdate")
        }
    }

    private fun handleFitnessExtendedData(value: ByteArray) {
        LogUtil.i(TAG, "handleFitnessExtendedData")
        var position = 0
        val flag = mGattParses.getIntValue(
            value,
            BluetoothGattCharacteristic.FORMAT_UINT16,
            position
        )
        position += 2
        LogUtil.i(TAG, "flag = $flag")
        if (flag and ByteConstant.BYTE_0X01 != 0) {
            var unlockCode = ""
            for (index in 0 until 6) {
                val code = mGattParses.getIntValue(
                    value,
                    BluetoothGattCharacteristic.FORMAT_UINT8,
                    position
                )
                position += 1
                unlockCode += code.toString()
            }
            mSportStatusData.mUnlockCode = unlockCode
            LogUtil.i(TAG, "unlockCode = ${mSportStatusData.mUnlockCode}")
        }
        if (flag and ByteConstant.BYTE_0X02 != 0) {
            val heartRate = mGattParses.getIntValue(
                value,
                BluetoothGattCharacteristic.FORMAT_UINT8,
                position
            )
            position += 1
            mSportStatusData.mHeartRate = heartRate
            LogUtil.i(TAG, "heartRate = $heartRate")
        }
        if (flag and ByteConstant.BYTE_0X04 != 0) {
            val totalEnergy = mGattParses.getIntValue(
                value,
                BluetoothGattCharacteristic.FORMAT_UINT16,
                position
            )
            position += 2
            mSportStatusData.mTotalEnergy = totalEnergy
            LogUtil.i(TAG, "totalEnergy = $totalEnergy")
        }
        if (flag and ByteConstant.BYTE_0X08 != 0) {
            val dynamicEnergy = mGattParses.getIntValue(
                value,
                BluetoothGattCharacteristic.FORMAT_UINT16,
                position
            )
            position += 2
            mSportStatusData.mDynamicEnergy = dynamicEnergy
            LogUtil.i(TAG, "dynamicEnergy = $dynamicEnergy")
        }
        if (flag and ByteConstant.BYTE_0X10 != 0) {
            val step = mGattParses.getIntValue(
                value,
                BluetoothGattCharacteristic.FORMAT_UINT16,
                position
            )
            position += 2
            mSportStatusData.mStepCount = step
            LogUtil.i(TAG, "step = $step")
        }
        if (flag and ByteConstant.BYTE_0X20 != 0) {
            val suppressAutoPause = mGattParses.getIntValue(
                value,
                BluetoothGattCharacteristic.FORMAT_UINT8,
                position
            )
            position += 1
            mSportStatusData.mSuppressAutoPause = suppressAutoPause
            LogUtil.i(TAG, "suppressAutoPause = $suppressAutoPause")
        }
        if (flag and ByteConstant.BYTE_0X40 != 0) {
            val targetedExpendedEnergy = mGattParses.getIntValue(
                value,
                BluetoothGattCharacteristic.FORMAT_UINT16,
                position
            )
            position += 2
            mSportStatusData.mTargetedExpendedEnergy = targetedExpendedEnergy
            LogUtil.i(TAG, "targetedExpendedEnergy = $targetedExpendedEnergy")
        }
    }

    private fun handleControlPoint(
        value: ByteArray,
        device: BluetoothDevice?,
        characteristic: BluetoothGattCharacteristic?
    ) {
        LogUtil.i(TAG, "handleControlPoint")
        var position = 0
        // 控制指令
        val opCode = mGattParses.getIntValue(
            value,
            BluetoothGattCharacteristic.FORMAT_SINT8,
            position
        )
        position += 1
        device ?: let {
            return
        }
        characteristic ?: let {
            return
        }
        when (opCode) {
            FitnessControlConstant.RequestControl -> {
                handleRequestControlAction(device, characteristic, opCode)
            }

            FitnessControlConstant.Reset -> {
                handleResetAction(device, characteristic, opCode)
            }

            FitnessControlConstant.SetTargetSpeed -> {
                handleSetTargetSpeedAction(device, characteristic, opCode, value, position)
            }

            FitnessControlConstant.SetTargetInclination -> {
                handleSetTargetInclinationAction(device, characteristic, opCode, value, position)
            }

            FitnessControlConstant.SetTargetResistanceLevel -> {
                handleSetTargetResistanceLevelAction(
                    device,
                    characteristic,
                    opCode,
                    value,
                    position
                )
            }

            FitnessControlConstant.SetTargetPower -> {
                handleSetTargetPowerAction(device, characteristic, opCode, value, position)
            }

            FitnessControlConstant.StartOrResume -> {
                handleStartOrResumeAction(device, characteristic, opCode)
            }

            FitnessControlConstant.StopOrPause -> {
                handleStopOrPauseAction(device, characteristic, opCode, value, position)
            }

            FitnessControlConstant.setTargetedCadence -> {
                handleSetTargetedCadenceAction(device, characteristic, opCode, value, position)
            }

            FitnessControlConstant.setTargetedDistance -> {
                handleSetTargetedDistanceAction(device, characteristic, opCode, value, position)
            }

            FitnessControlConstant.setTargetedTrainingTime -> {
                handleSetTargetedTrainingTimeAction(device, characteristic, opCode, value, position)
            }

            else -> {
                if (!mSportStatusData.mIsAllowControl) {
                    notifyControlUnAllow(device, characteristic, opCode)
                    return
                }
                // 回复不支持
                notifyControlUnSupport(device, characteristic, opCode)
            }
        }
    }

    private fun handleSetTargetedTrainingTimeAction(
        device: BluetoothDevice,
        characteristic: BluetoothGattCharacteristic,
        opCode: Int,
        value: ByteArray,
        position: Int
    ) {
        if (!mSportStatusData.mIsAllowControl) {
            notifyControlUnAllow(device, characteristic, opCode)
            return
        }
        val targetSettingFeaturesFlag =
            sportViewModel.fitnessConfigData?.targetSettingFeaturesFlag as Int
        if (targetSettingFeaturesFlag and ByteConstant.BYTE_0x200 == 0) {
            notifyControlUnSupport(device, characteristic, opCode)
            return
        }
        if (value.size < 3) {
            notifyControlParameterError(device, characteristic, opCode)
            return
        }
        // 目标时间，需要记录，开启运动后，达到目标时间就停止
        val targetedTrainingTime = mGattParses.getIntValue(
            value,
            BluetoothGattCharacteristic.FORMAT_UINT16,
            position
        )
        LogUtil.i(TAG, "targetedTrainingTime = $targetedTrainingTime")
        mSportStatusData.mTargetedTrainingTime = targetedTrainingTime
        // 回复设置结果
        notifyControlSuccess(device, characteristic, opCode)
        val byteArray = ByteArray(3)
        ByteUtil.intToOneByteArray(
            byteArray,
            FitnessMachineStatusConstant.targetedTrainingTimeChanged,
            0
        )
        ByteUtil.intToTwoByteArray(byteArray, mSportStatusData.mTargetedTrainingTime, 1)
        mBlueMessageQueue.addNotifyMessage(
            byteArray,
            device,
            mFitnessMachineStatusCharacteristic
        )
    }

    private fun handleSetTargetedDistanceAction(
        device: BluetoothDevice,
        characteristic: BluetoothGattCharacteristic,
        opCode: Int,
        value: ByteArray,
        position: Int
    ) {
        if (!mSportStatusData.mIsAllowControl) {
            notifyControlUnAllow(device, characteristic, opCode)
            return
        }
        val targetSettingFeaturesFlag =
            sportViewModel.fitnessConfigData?.targetSettingFeaturesFlag as Int
        if (targetSettingFeaturesFlag and ByteConstant.BYTE_0x100 == 0) {
            notifyControlUnSupport(device, characteristic, opCode)
            return
        }
        if (value.size < 4) {
            notifyControlParameterError(device, characteristic, opCode)
            return
        }
        // uint24
        // 目标距离，需要记录，开启运动后，达到目标距离就停止
        val targetedDistance = mGattParses.getIntValue(
            value,
            GattParses.FORMAT_UINT24,
            position
        )
        LogUtil.i(TAG, "targetedDistance = $targetedDistance")
        mSportStatusData.mTargetedDistance = targetedDistance
        notifyControlSuccess(device, characteristic, opCode)
        val byteArray = ByteArray(4)
        ByteUtil.intToOneByteArray(
            byteArray,
            FitnessMachineStatusConstant.targetedDistanceChanged,
            0
        )
        ByteUtil.intToThreeByteArray(byteArray, mSportStatusData.mTargetedDistance, 1)
        mBlueMessageQueue.addNotifyMessage(
            byteArray,
            device,
            mFitnessMachineStatusCharacteristic
        )
    }

    private fun handleSetTargetedCadenceAction(
        device: BluetoothDevice,
        characteristic: BluetoothGattCharacteristic,
        opCode: Int,
        value: ByteArray,
        position: Int
    ) {
        if (!mSportStatusData.mIsAllowControl) {
            notifyControlUnAllow(device, characteristic, opCode)
            return
        }
        val targetSettingFeaturesFlag =
            sportViewModel.fitnessConfigData?.targetSettingFeaturesFlag as Int
        if (targetSettingFeaturesFlag and ByteConstant.BYTE_0x10000 == 0) {
            notifyControlUnSupport(device, characteristic, opCode)
            return
        }
        if (value.size < 3) {
            notifyControlParameterError(device, characteristic, opCode)
            return
        }
        val targetedCadence = mGattParses.getIntValue(
            value,
            BluetoothGattCharacteristic.FORMAT_UINT16,
            position
        )
        LogUtil.i(TAG, "targetedCadence = $targetedCadence")
        mSportStatusData.mTargetedCadence = targetedCadence
        notifyControlSuccess(device, characteristic, opCode)
        val byteArray = ByteArray(3)
        ByteUtil.intToOneByteArray(
            byteArray,
            FitnessMachineStatusConstant.targetedCadenceChanged,
            0
        )
        ByteUtil.intToTwoByteArray(byteArray, mSportStatusData.mTargetedCadence, 1)
        mBlueMessageQueue.addNotifyMessage(
            byteArray,
            device,
            mFitnessMachineStatusCharacteristic
        )
    }

    private fun handleStopOrPauseAction(
        device: BluetoothDevice,
        characteristic: BluetoothGattCharacteristic,
        opCode: Int,
        value: ByteArray,
        position: Int
    ) {
        if (!mSportStatusData.mIsAllowControl) {
            notifyControlUnAllow(device, characteristic, opCode)
            return
        }
        if (value.size < 2) {
            notifyControlParameterError(device, characteristic, opCode)
            return
        }
        // 停止或暂停运动
        // Control Information; 01:stop;02:Pause;Other:RFU
        val parameter = mGattParses.getIntValue(
            value,
            BluetoothGattCharacteristic.FORMAT_SINT8,
            position
        )
        LogUtil.i(TAG, "StopOrPause = $parameter")
        when (parameter) {
            1 -> {
                mSportStatusData.mSportStatus = SportStatusData.SPORT_STOP
            }

            2 -> {
                mSportStatusData.mSportStatus = SportStatusData.SPORT_PAUSE
            }

            else -> {
                notifyControlParameterError(device, characteristic, opCode)
                return
            }
        }
        val trainingStatusNotifyFactory =
            mNotifyFactory.createFactory(FitnessProtocolConstant.TrainingStatus)
        trainingStatusNotifyFactory ?: let {
            LogUtil.e(TAG, "trainingStatusNotifyFactory is null")
            return
        }
        // 获取待发送的Training Status数据
        val trainingStatusByteArray =
            trainingStatusNotifyFactory.getNotifyByteArray(
                mSportStatusData.mSportStatus,
                sportViewModel.fitnessConfigData
            )
        // 发送Training Status状态，添加到消息队列中进行发送
        mBlueMessageQueue.addNotifyMessage(
            trainingStatusByteArray,
            device,
            mTrainingStatusCharacteristic
        )
        val fitnessMachineStatusNotifyFactory =
            mNotifyFactory.createFactory(FitnessProtocolConstant.FitnessMachineStatus)
        fitnessMachineStatusNotifyFactory ?: let {
            LogUtil.e(TAG, "fitnessMachineStatusNotifyFactory is null")
            return
        }
        val fitnessMachineStatusByteArray =
            fitnessMachineStatusNotifyFactory.getNotifyByteArray(
                mSportStatusData.mSportStatus,
                sportViewModel.fitnessConfigData
            )
        // 发送FitnessMachineStatus状态，添加到消息队列中进行发送
        mBlueMessageQueue.addNotifyMessage(
            fitnessMachineStatusByteArray,
            device,
            mFitnessMachineStatusCharacteristic
        )
        notifyControlSuccess(device, characteristic, opCode)
    }

    private fun handleStartOrResumeAction(
        device: BluetoothDevice,
        characteristic: BluetoothGattCharacteristic,
        opCode: Int
    ) {
        // 启动或恢复运动 无参数
        if (!mSportStatusData.mIsAllowControl) {
            notifyControlUnAllow(device, characteristic, opCode)
            return
        }
        mSportStatusData.mSportStatus = SportStatusData.SPORT_SPORTING
        // 使用消息队列，完成所有消息发送
        val trainingStatusNotifyFactory =
            mNotifyFactory.createFactory(FitnessProtocolConstant.TrainingStatus)
        trainingStatusNotifyFactory ?: let {
            LogUtil.e(TAG, "trainingStatusNotifyFactory is null")
            return
        }
        // 获取待发送的Training Status数据
        val trainingStatusByteArray =
            trainingStatusNotifyFactory.getNotifyByteArray(
                mSportStatusData.mSportStatus,
                sportViewModel.fitnessConfigData
            )
        // 发送Training Status状态，添加到消息队列中进行发送
        mBlueMessageQueue.addNotifyMessage(
            trainingStatusByteArray,
            device,
            mTrainingStatusCharacteristic
        )

        val fitnessMachineStatusNotifyFactory =
            mNotifyFactory.createFactory(FitnessProtocolConstant.FitnessMachineStatus)
        fitnessMachineStatusNotifyFactory ?: let {
            LogUtil.e(TAG, "fitnessMachineStatusNotifyFactory is null")
            return
        }
        val fitnessMachineStatusByteArray =
            fitnessMachineStatusNotifyFactory.getNotifyByteArray(
                mSportStatusData.mSportStatus,
                sportViewModel.fitnessConfigData
            )
        // 发送FitnessMachineStatus状态，添加到消息队列中进行发送
        mBlueMessageQueue.addNotifyMessage(
            fitnessMachineStatusByteArray,
            device,
            mFitnessMachineStatusCharacteristic
        )
        looperSendRealTimeData(device)
    }

    private fun handleSetTargetPowerAction(
        device: BluetoothDevice,
        characteristic: BluetoothGattCharacteristic,
        opCode: Int,
        value: ByteArray,
        position: Int
    ) {
        if (!mSportStatusData.mIsAllowControl) {
            notifyControlUnAllow(device, characteristic, opCode)
            return
        }
        val targetSettingFeaturesFlag =
            sportViewModel.fitnessConfigData?.targetSettingFeaturesFlag as Int
        if (targetSettingFeaturesFlag and ByteConstant.BYTE_0X08 == 0) {
            notifyControlUnSupport(device, characteristic, opCode)
            return
        }
        if (value.size < 3) {
            notifyControlParameterError(device, characteristic, opCode)
            return
        }
        val targetedPower = mGattParses.getIntValue(
            value,
            BluetoothGattCharacteristic.FORMAT_UINT16,
            position
        )
        LogUtil.i(TAG, "targetedPower = $targetedPower")
        mSportStatusData.mTargetedPower = targetedPower
        notifyControlSuccess(device, characteristic, opCode)
        val byteArray = ByteArray(3)
        ByteUtil.intToOneByteArray(byteArray, FitnessMachineStatusConstant.TargetPowerChanged, 0)
        ByteUtil.intToTwoByteArray(byteArray, mSportStatusData.mTargetedPower, 1)
        mBlueMessageQueue.addNotifyMessage(
            byteArray,
            device,
            mFitnessMachineStatusCharacteristic
        )
    }

    private fun handleSetTargetResistanceLevelAction(
        device: BluetoothDevice,
        characteristic: BluetoothGattCharacteristic,
        opCode: Int,
        value: ByteArray,
        position: Int
    ) {
        if (!mSportStatusData.mIsAllowControl) {
            notifyControlUnAllow(device, characteristic, opCode)
            return
        }
        val targetSettingFeaturesFlag =
            sportViewModel.fitnessConfigData?.targetSettingFeaturesFlag as Int
        if (targetSettingFeaturesFlag and ByteConstant.BYTE_0X04 == 0) {
            notifyControlUnSupport(device, characteristic, opCode)
            return
        }
        if (value.size < 2) {
            notifyControlParameterError(device, characteristic, opCode)
            return
        }
        val targetedResistanceLevel = mGattParses.getIntValue(
            value,
            BluetoothGattCharacteristic.FORMAT_UINT8,
            position
        )
        LogUtil.i(TAG, "targetedResistanceLevel = $targetedResistanceLevel")
        mSportStatusData.mTargetedResistanceLevel = targetedResistanceLevel
        notifyControlSuccess(device, characteristic, opCode)
        val byteArray = ByteArray(2)
        ByteUtil.intToOneByteArray(
            byteArray,
            FitnessMachineStatusConstant.targetResistanceLevelChanged,
            0
        )
        ByteUtil.intToOneByteArray(byteArray, mSportStatusData.mTargetedResistanceLevel, 1)
        mBlueMessageQueue.addNotifyMessage(
            byteArray,
            device,
            mFitnessMachineStatusCharacteristic
        )
    }

    private fun handleSetTargetInclinationAction(
        device: BluetoothDevice,
        characteristic: BluetoothGattCharacteristic,
        opCode: Int,
        value: ByteArray,
        position: Int
    ) {
        if (!mSportStatusData.mIsAllowControl) {
            notifyControlUnAllow(device, characteristic, opCode)
            return
        }
        val targetSettingFeaturesFlag =
            sportViewModel.fitnessConfigData?.targetSettingFeaturesFlag as Int
        if (targetSettingFeaturesFlag and ByteConstant.BYTE_0X02 == 0) {
            notifyControlUnSupport(device, characteristic, opCode)
            return
        }
        if (value.size < 3) {
            notifyControlParameterError(device, characteristic, opCode)
            return
        }
        val targetedInclination = mGattParses.getIntValue(
            value,
            BluetoothGattCharacteristic.FORMAT_UINT16,
            position
        )
        LogUtil.i(TAG, "targetedInclination = $targetedInclination")
        mSportStatusData.mTargetedInclination = targetedInclination
        notifyControlSuccess(device, characteristic, opCode)
        val byteArray = ByteArray(3)
        ByteUtil.intToOneByteArray(byteArray, FitnessMachineStatusConstant.targetInclineChanged, 0)
        ByteUtil.intToTwoByteArray(byteArray, mSportStatusData.mTargetedInclination, 1)
        mBlueMessageQueue.addNotifyMessage(
            byteArray,
            device,
            mFitnessMachineStatusCharacteristic
        )
    }

    private fun handleResetAction(
        device: BluetoothDevice,
        characteristic: BluetoothGattCharacteristic,
        opCode: Int
    ) {
        if (!mSportStatusData.mIsAllowControl) {
            notifyControlUnAllow(device, characteristic, opCode)
            return
        }
        // 此指令需要请求控制权限（RequestControl），会复位对应的目标值，比如speed等
        mSportStatusData.mUnlockCode = ""
        mSportStatusData.mSportStatus = SportStatusData.SPORT_IDLE
        mSportStatusData.mHeartRate = 0
        mSportStatusData.mTotalEnergy = 0
        mSportStatusData.mDynamicEnergy = 0
        mSportStatusData.mSuppressAutoPause = 0
        mSportStatusData.mTargetedExpendedEnergy = 0
        mSportStatusData.mTargetedSpeed = 0
        mSportStatusData.mTargetedInclination = 0
        mSportStatusData.mTargetedResistanceLevel = 0
        mSportStatusData.mTargetedPower = 0
        mSportStatusData.mTargetedDistance = 0
        mSportStatusData.mTargetedTrainingTime = 0
        notifyControlSuccess(device, characteristic, opCode)
        mBlueMessageQueue.addNotifyMessage(
            byteArrayOf(1),
            device,
            mFitnessMachineStatusCharacteristic
        )
    }

    private fun handleRequestControlAction(
        device: BluetoothDevice,
        characteristic: BluetoothGattCharacteristic,
        opCode: Int
    ) {
        // 请求控制结果一直保持到运动断开连接,如果是已授权，则直接返回结果
        if (mSportStatusData.mIsAllowControl) {
            notifyControlSuccess(device, characteristic, opCode)
            return
        }
        // 判断设备类型，如果是跑步机，需要接受到解锁码，解锁码一致才允许回复允许控制
        if (deviceType == DeviceConstant.treadmill && mSportStatusData.mUnlockCode != sportViewModel.fitnessConfigData?.unlockCode) {
            notifyControlUnAllow(device, characteristic, opCode)
            return
        }
        // 其他情况请求控制成功,特殊情况再额外设置
        mSportStatusData.mIsAllowControl = true
        LogUtil.i(TAG, "AllowControl")
        notifyControlSuccess(device, characteristic, opCode)
    }

    private fun handleSetTargetSpeedAction(
        device: BluetoothDevice,
        characteristic: BluetoothGattCharacteristic,
        opCode: Int,
        value: ByteArray,
        position: Int
    ) {
        if (!mSportStatusData.mIsAllowControl) {
            notifyControlUnAllow(device, characteristic, opCode)
            return
        }
        val targetSettingFeaturesFlag =
            sportViewModel.fitnessConfigData?.targetSettingFeaturesFlag as Int
        if (targetSettingFeaturesFlag and ByteConstant.BYTE_0X01 == 0) {
            notifyControlUnSupport(device, characteristic, opCode)
            return
        }
        if (value.size < 3) {
            notifyControlParameterError(device, characteristic, opCode)
            return
        }
        val targetedSpeed = mGattParses.getIntValue(
            value,
            BluetoothGattCharacteristic.FORMAT_UINT16,
            position
        )
        LogUtil.i(TAG, "targetedSpeed = $targetedSpeed")
        mSportStatusData.mTargetedSpeed = targetedSpeed
        notifyControlSuccess(device, characteristic, opCode)
        // notify Fitness Machine Status
        val byteArray = ByteArray(3)
        ByteUtil.intToOneByteArray(byteArray, FitnessMachineStatusConstant.targetSpeedChanged, 0)
        ByteUtil.intToTwoByteArray(byteArray, mSportStatusData.mTargetedSpeed, 1)
        mBlueMessageQueue.addNotifyMessage(
            byteArray,
            device,
            mFitnessMachineStatusCharacteristic
        )
    }

    /**
     * 循环发送实时数据
     */
    private fun looperSendRealTimeData(device: BluetoothDevice) {
        LogUtil.i(TAG, "looperSendRealTimeData")
        // 根据对应设备类型，启动实时运动数据循环发送
        var realTimeDataFactory: INotifyFactory? = null
        var bluetoothGattCharacteristic: BluetoothGattCharacteristic? = null
        when (deviceType) {
            DeviceConstant.treadmill -> {
                realTimeDataFactory =
                    mNotifyFactory.createFactory(FitnessProtocolConstant.TreadmillData)
                bluetoothGattCharacteristic = mTreadmillDataCharacteristic
            }

            DeviceConstant.indoorBike -> {
                realTimeDataFactory =
                    mNotifyFactory.createFactory(FitnessProtocolConstant.IndoorBikeData)
                bluetoothGattCharacteristic = mIndoorBikeDataCharacteristic
            }

            DeviceConstant.crossTrainer -> {
                realTimeDataFactory =
                    mNotifyFactory.createFactory(FitnessProtocolConstant.CrossTrainerData)
                bluetoothGattCharacteristic = mCrossTrainerDataCharacteristic
            }

            DeviceConstant.rower -> {
                realTimeDataFactory =
                    mNotifyFactory.createFactory(FitnessProtocolConstant.RowerData)
                bluetoothGattCharacteristic = mRowerDataCharacteristic
            }
        }
        realTimeDataFactory ?: let {
            LogUtil.e(TAG, "realTimeDataFactory is null")
            return
        }
        bluetoothGattCharacteristic ?: let {
            LogUtil.e(TAG, "bluetoothGattCharacteristic is null")
            return
        }
        // 只有在运动中才开始发送
        if (mSportStatusData.mSportStatus != SportStatusData.SPORT_SPORTING) {
            return
        }
        val realTimeDataByteArrayList =
            realTimeDataFactory.getNotifyByteArrayList(
                mSportStatusData.mSportStatus,
                sportViewModel.fitnessConfigData
            )
        for (realTimeDataByteArray in realTimeDataByteArrayList) {
            LogUtil.i(TAG, "byteArray =  ${ByteUtil.bytesToHexString(realTimeDataByteArray)}")
            // 添加到消息队列中进行发送
            mBlueMessageQueue.addNotifyMessage(
                realTimeDataByteArray,
                device,
                bluetoothGattCharacteristic
            )
        }

        // 间隔100ms,再次调用此方法
        val message = mBlueMessageQueueHandler.obtainMessage()
        val bundle = Bundle()
        bundle.putParcelable(DEVICE, device)
        message.what = SEND_REAL_TIME_DATA
        message.data = bundle
        mBlueMessageQueueHandler.sendMessageDelayed(message, 500)
    }

    override fun onDestroy() {
        super.onDestroy()
        mBluetoothLeAdvertiser?.stopAdvertising(mAdvertiseCallback)
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityBleServerBinding.inflate(layoutInflater)
        setContentView(binding.root)
        binding.linearLayoutCompatConfigBack.setOnClickListener {
            finish()
        }
        intent ?: let {
            LogUtil.i(TAG, "intent is null")
            return
        }
        deviceType = intent.getStringExtra(DeviceConstant.deviceType) as String
        if (!packageManager.hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
            ToastUtil.toastShort("ble not support")
            return
        }
        mResponseFactory = ResponseFactory()
        mBluetoothManager = getSystemService(BLUETOOTH_SERVICE) as BluetoothManager
        mBluetoothManager ?: let {
            ToastUtil.toastShort("mBluetoothManager not support")
            displayInfo("蓝牙环境出错")
            return
        }
        mBluetoothAdapter = mBluetoothManager?.adapter
        if (mBluetoothAdapter == null) {
            ToastUtil.toastShort("bluetooth not support")
            displayInfo("蓝牙环境出错")
            return
        }
        mBluetoothLeAdvertiser = mBluetoothAdapter?.bluetoothLeAdvertiser
        if (mBluetoothLeAdvertiser == null) {
            ToastUtil.toastShort("the device not support peripheral")
            displayInfo("该手机芯片不支持BLE广播")
            return
        }
        displayInfo("设备类型: $deviceType")
        mHandlerThread = HandlerThread(TAG)
        mHandlerThread.start()
        mBlueMessageQueueHandler = BlueMessageQueueHandler(mHandlerThread.looper)
        mGattParses = GattParses()
        mNotifyFactory = NotifyFactory()
        mSportStatusData = SportStatusData()
        mBlueMessageQueue = BlueMessageQueue()
        mBlueMessageQueue.setBlueMessageQueueListen(mBlueMessageQueueCallback)
        createService()
        openGattServer()
        binding.buttonStartAdvertising.setOnClickListener {
            lifecycleScope.launch {
                val deviceInfo = deviceInfoViewModel.getDeviceInfo(deviceType)
                LogUtil.i(TAG, "deviceInfo = ${deviceInfo.toString()}")
                deviceInfo ?: let {
                    ToastUtil.toastShort("请点击右上角配置按钮进行配置器械配置")
                    return@launch
                }
                val featuresData = featuresViewModel.getFeaturesData(deviceType)
                featuresData ?: let {
                    ToastUtil.toastShort("请点击右上角配置按钮进行配置器械配置")
                    return@launch
                }
                val supportRangeDataList = supportRangeViewModel.getSupportRangeList(deviceType)
                if (supportRangeDataList.isEmpty()) {
                    ToastUtil.toastShort("请点击右上角配置按钮进行配置器械配置")
                    return@launch
                }
                val fitnessConfigData = FitnessConfigData()
                fitnessConfigData.unlockCode = deviceInfo.unlockCode
                fitnessConfigData.systemId = deviceInfo.systemId
                fitnessConfigData.modelNumber = deviceInfo.modelNumber
                fitnessConfigData.serialNumber = deviceInfo.serialNumber
                fitnessConfigData.firmwareRevision = deviceInfo.firmwareRevision
                fitnessConfigData.hardwareRevision = deviceInfo.hardwareRevision
                fitnessConfigData.softwareRevision = deviceInfo.softwareRevision
                fitnessConfigData.manufacturerName = deviceInfo.manufacturerName
                fitnessConfigData.manufacturerName = deviceInfo.manufacturerName
                fitnessConfigData.fitnessMachineFeaturesFlag =
                    featuresData.fitnessMachineFeaturesFlag
                fitnessConfigData.targetSettingFeaturesFlag = featuresData.targetSettingFeaturesFlag
                for (supportRange in supportRangeDataList) {
                    when (supportRange.supportRangeType) {
                        FitnessConfigData.SUPPORT_SPEED -> {
                            fitnessConfigData.minSpeed = supportRange.minValue
                            fitnessConfigData.maxSpeed = supportRange.maxValue
                            fitnessConfigData.minSpeedIncrement = supportRange.minIncrement
                        }

                        FitnessConfigData.SUPPORT_POWER -> {
                            fitnessConfigData.minPower = supportRange.minValue
                            fitnessConfigData.maxPower = supportRange.maxValue
                            fitnessConfigData.minPowerIncrement = supportRange.minIncrement
                        }

                        FitnessConfigData.SUPPORT_HEART_RATE -> {
                            fitnessConfigData.minHeartRate = supportRange.minValue
                            fitnessConfigData.maxHeartRate = supportRange.maxValue
                            fitnessConfigData.minHeartRateIncrement = supportRange.minIncrement
                        }

                        FitnessConfigData.SUPPORT_INCLINATION -> {
                            fitnessConfigData.minInclination = supportRange.minValue
                            fitnessConfigData.maxInclination = supportRange.maxValue
                            fitnessConfigData.minInclinationIncrement = supportRange.minIncrement
                        }

                        FitnessConfigData.SUPPORT_RESISTANCE_LEVEL -> {
                            fitnessConfigData.minResistanceLevel = supportRange.minValue
                            fitnessConfigData.maxResistanceLevel = supportRange.maxValue
                            fitnessConfigData.minResistanceLevelIncrement =
                                supportRange.minIncrement
                        }
                    }
                }
                sportViewModel.fitnessConfigData = fitnessConfigData
                startAdvertising()
            }
        }
        binding.buttonStopAdvertising.setOnClickListener {
            stopAdvertising()
        }
        binding.buttonClean.setOnClickListener {
            binding.textViewDisplayView.text = ""
        }
        binding.textViewConfig.setOnClickListener {
            val intent = Intent()
            intent.putExtra(DeviceConstant.deviceType, deviceType)
            intent.setClass(this, ConfigActivity::class.java)
            startActivity(intent)
        }
    }

    /**
     * 展示信息
     */
    private fun displayInfo(infoStr: String) {
        runOnUiThread {
            binding.textViewDisplayView.text =
                binding.textViewDisplayView.text.toString() + "\n $infoStr"
        }
    }

    /**
     * 开启广播
     */
    private fun startAdvertising() {
        LogUtil.i(TAG, "startAdvertising")
        // scanResponse可以调用createScanAdvertiseData
        mBluetoothLeAdvertiser?.startAdvertising(
            createAdvSetting(true, 0),
            createAdvertiseData(),
            mAdvertiseCallback
        )
        displayInfo("开启Ble广播")
    }

    /**
     * 关闭广播
     */
    private fun stopAdvertising() {
        LogUtil.i(TAG, "stopAdvertising")
        mBluetoothLeAdvertiser?.stopAdvertising(mAdvertiseCallback)
        displayInfo("停止Ble广播")
    }

    /**
     * 广播设置
     */
    private fun createAdvSetting(connectAble: Boolean, timeoutMillis: Int): AdvertiseSettings {
        val settingBuilder: AdvertiseSettings.Builder = AdvertiseSettings.Builder()
        settingBuilder.setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_LOW_LATENCY)
        settingBuilder.setConnectable(connectAble)
        settingBuilder.setTimeout(timeoutMillis)
        settingBuilder.setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_HIGH)
        return settingBuilder.build()
    }

    /**
     * 广播数据设置(必须，广播启动就会发送)
     */
    private fun createAdvertiseData(): AdvertiseData {
        val dataBuilder: AdvertiseData.Builder = AdvertiseData.Builder()
        dataBuilder.addServiceUuid(ParcelUuid.fromString(FitnessProtocolConstant.FitnessMachineServiceString))
        // 如果启动失败，报错错误码是1，代表广播数据超过了31字节，可能是蓝牙名称太长导致，需要更改蓝牙名称变短一点
        dataBuilder.setIncludeDeviceName(true)
        var fitnessMachineType = 0
        when (deviceType) {
            DeviceConstant.treadmill -> {
                fitnessMachineType = ByteConstant.BYTE_0X01
            }

            DeviceConstant.crossTrainer -> {
                fitnessMachineType = ByteConstant.BYTE_0X02
            }

            DeviceConstant.rower -> {
                fitnessMachineType = ByteConstant.BYTE_0X08
            }

            DeviceConstant.indoorBike -> {
                fitnessMachineType = ByteConstant.BYTE_0X10
            }
        }
        LogUtil.i(TAG, "fitnessMachineType = $fitnessMachineType")
        val serverData = ByteArray(3)
        var position = 0
        ByteUtil.intToOneByteArray(serverData, 1, position)
        position++
        ByteUtil.intToTwoByteArray(serverData, fitnessMachineType, position)
        LogUtil.i(
            TAG,
            "serverData = ${ByteUtil.bytesToHexString(serverData)} serverData.size = ${serverData.size}"
        )
        dataBuilder.addServiceData(
            ParcelUuid.fromString(FitnessProtocolConstant.FitnessMachineServiceString),
            serverData
        )
        val manufacturerSpecificData = ByteArray(5)
        var manufacturerSpecificDataPosition = 0
        ByteUtil.intToOneByteArray(manufacturerSpecificData, 1, manufacturerSpecificDataPosition)
        manufacturerSpecificDataPosition++
        ByteUtil.intToOneByteArray(manufacturerSpecificData, 5, manufacturerSpecificDataPosition)
        manufacturerSpecificDataPosition++
        ByteUtil.intToOneByteArray(manufacturerSpecificData, 0, manufacturerSpecificDataPosition)
        manufacturerSpecificDataPosition++
        ByteUtil.intToOneByteArray(manufacturerSpecificData, 255, manufacturerSpecificDataPosition)
        manufacturerSpecificDataPosition++
        ByteUtil.intToOneByteArray(manufacturerSpecificData, 255, manufacturerSpecificDataPosition)
        LogUtil.i(
            TAG,
            "manufacturerSpecificData = ${ByteUtil.bytesToHexString(manufacturerSpecificData)}"
        )
        dataBuilder.addManufacturerData(0x027d, manufacturerSpecificData)
        return dataBuilder.build()
    }

    /**
     * 扫描响应数据(可选，当客户端扫描时才发送)
     */
    private fun createScanAdvertiseData(): AdvertiseData {
        val dataBuilder: AdvertiseData.Builder = AdvertiseData.Builder()
        dataBuilder.addServiceUuid(ParcelUuid.fromString(FitnessProtocolConstant.FitnessMachineServiceString))
        // 如果启动失败，报错错误码是1，代表广播数据超过了31字节，可能是蓝牙名称太长导致，需要更改蓝牙名称变短一点
        dataBuilder.setIncludeDeviceName(true)
        var fitnessMachineType = 0
        when (deviceType) {
            DeviceConstant.treadmill -> {
                fitnessMachineType = ByteConstant.BYTE_0X01
            }

            DeviceConstant.crossTrainer -> {
                fitnessMachineType = ByteConstant.BYTE_0X02
            }

            DeviceConstant.rower -> {
                fitnessMachineType = ByteConstant.BYTE_0X08
            }

            DeviceConstant.indoorBike -> {
                fitnessMachineType = ByteConstant.BYTE_0X10
            }
        }
        LogUtil.i(TAG, "fitnessMachineType = $fitnessMachineType")
        val serverData = ByteArray(3)
        var position = 0
        ByteUtil.intToOneByteArray(serverData, 1, position)
        position++
        ByteUtil.intToTwoByteArray(serverData, fitnessMachineType, position)
        LogUtil.i(
            TAG,
            "serverData = ${ByteUtil.bytesToHexString(serverData)} serverData.size = ${serverData.size}"
        )
        dataBuilder.addServiceData(
            ParcelUuid.fromString(FitnessProtocolConstant.FitnessMachineServiceString),
            serverData
        )
        val manufacturerSpecificData = ByteArray(5)
        var manufacturerSpecificDataPosition = 0
        ByteUtil.intToOneByteArray(manufacturerSpecificData, 1, manufacturerSpecificDataPosition)
        manufacturerSpecificDataPosition++
        ByteUtil.intToOneByteArray(manufacturerSpecificData, 5, manufacturerSpecificDataPosition)
        manufacturerSpecificDataPosition++
        ByteUtil.intToOneByteArray(manufacturerSpecificData, 0, manufacturerSpecificDataPosition)
        manufacturerSpecificDataPosition++
        ByteUtil.intToOneByteArray(manufacturerSpecificData, 255, manufacturerSpecificDataPosition)
        manufacturerSpecificDataPosition++
        ByteUtil.intToOneByteArray(manufacturerSpecificData, 255, manufacturerSpecificDataPosition)
        LogUtil.i(
            TAG,
            "manufacturerSpecificData = ${ByteUtil.bytesToHexString(manufacturerSpecificData)}"
        )
        dataBuilder.addManufacturerData(0x027d, manufacturerSpecificData)
        return dataBuilder.build()
    }

    /**
     * 创建服务、特征值等信息
     */
    private fun createService() {
        createDisService()
        createFitnessService()
        displayInfo("初始化Dis与FTMP服务成功")
    }

    /**
     * 创建FTMP服务与特征值 每一个BluetoothGattCharacteristic必须单独使用一个BluetoothGattDescriptor，要不会导致
     * 分配handle的时候出现找不到对应的特征的情况，BluetoothGattDescriptor不能公用一个
     */
    private fun createFitnessService() {
        val fitnessMachineFeatureDescriptor =
            BluetoothGattDescriptor(
                FitnessProtocolConstant.Descriptor,
                BluetoothGattDescriptor.PERMISSION_READ
            )
        mFitnessMachineFeatureCharacteristic = BluetoothGattCharacteristic(
            FitnessProtocolConstant.FitnessMachineFeature,
            BluetoothGattCharacteristic.PROPERTY_READ,
            BluetoothGattCharacteristic.PERMISSION_READ
        )
        mFitnessMachineFeatureCharacteristic.addDescriptor(fitnessMachineFeatureDescriptor)

        val treadmillDataDescriptor =
            BluetoothGattDescriptor(
                FitnessProtocolConstant.Descriptor,
                BluetoothGattDescriptor.PERMISSION_WRITE
            )
        val treadmillDataDescriptorUser =
            BluetoothGattDescriptor(
                FitnessProtocolConstant.Descriptor_USER,
                BluetoothGattDescriptor.PERMISSION_WRITE
            )
        mTreadmillDataCharacteristic = BluetoothGattCharacteristic(
            FitnessProtocolConstant.TreadmillData,
            BluetoothGattCharacteristic.PROPERTY_NOTIFY,
            BluetoothGattCharacteristic.PERMISSION_WRITE
        )
        mTreadmillDataCharacteristic.addDescriptor(treadmillDataDescriptor)
        mTreadmillDataCharacteristic.addDescriptor(treadmillDataDescriptorUser)

        val crossTrainerDataDescriptor =
            BluetoothGattDescriptor(
                FitnessProtocolConstant.Descriptor,
                BluetoothGattDescriptor.PERMISSION_WRITE
            )
        val crossTrainerDataDescriptorUser =
            BluetoothGattDescriptor(
                FitnessProtocolConstant.Descriptor_USER,
                BluetoothGattDescriptor.PERMISSION_WRITE
            )
        mCrossTrainerDataCharacteristic = BluetoothGattCharacteristic(
            FitnessProtocolConstant.CrossTrainerData,
            BluetoothGattCharacteristic.PROPERTY_NOTIFY,
            BluetoothGattCharacteristic.PERMISSION_WRITE
        )
        mCrossTrainerDataCharacteristic.addDescriptor(crossTrainerDataDescriptor)
        mCrossTrainerDataCharacteristic.addDescriptor(crossTrainerDataDescriptorUser)

        val rowerDataDescriptor =
            BluetoothGattDescriptor(
                FitnessProtocolConstant.Descriptor,
                BluetoothGattDescriptor.PERMISSION_WRITE
            )
        val rowerDataDescriptorUser =
            BluetoothGattDescriptor(
                FitnessProtocolConstant.Descriptor_USER,
                BluetoothGattDescriptor.PERMISSION_WRITE
            )
        mRowerDataCharacteristic = BluetoothGattCharacteristic(
            FitnessProtocolConstant.RowerData,
            BluetoothGattCharacteristic.PROPERTY_NOTIFY,
            BluetoothGattCharacteristic.PERMISSION_WRITE
        )
        mRowerDataCharacteristic.addDescriptor(rowerDataDescriptor)
        mRowerDataCharacteristic.addDescriptor(rowerDataDescriptorUser)

        val indoorBikeDataDescriptor =
            BluetoothGattDescriptor(
                FitnessProtocolConstant.Descriptor,
                BluetoothGattDescriptor.PERMISSION_WRITE
            )
        val indoorBikeDataDescriptorUser =
            BluetoothGattDescriptor(
                FitnessProtocolConstant.Descriptor_USER,
                BluetoothGattDescriptor.PERMISSION_WRITE
            )
        mIndoorBikeDataCharacteristic = BluetoothGattCharacteristic(
            FitnessProtocolConstant.IndoorBikeData,
            BluetoothGattCharacteristic.PROPERTY_NOTIFY,
            BluetoothGattCharacteristic.PERMISSION_WRITE
        )
        mIndoorBikeDataCharacteristic.addDescriptor(indoorBikeDataDescriptor)
        mIndoorBikeDataCharacteristic.addDescriptor(indoorBikeDataDescriptorUser)

        val trainingStatusDescriptor =
            BluetoothGattDescriptor(
                FitnessProtocolConstant.Descriptor,
                BluetoothGattDescriptor.PERMISSION_WRITE or BluetoothGattDescriptor.PERMISSION_READ
            )
        val trainingStatusDescriptorUser =
            BluetoothGattDescriptor(
                FitnessProtocolConstant.Descriptor_USER,
                BluetoothGattDescriptor.PERMISSION_WRITE
            )
        mTrainingStatusCharacteristic = BluetoothGattCharacteristic(
            FitnessProtocolConstant.TrainingStatus,
            BluetoothGattCharacteristic.PROPERTY_NOTIFY or BluetoothGattCharacteristic.PROPERTY_READ,
            BluetoothGattCharacteristic.PERMISSION_WRITE or BluetoothGattCharacteristic.PERMISSION_READ
        )
        mTrainingStatusCharacteristic.addDescriptor(trainingStatusDescriptor)
        mTrainingStatusCharacteristic.addDescriptor(trainingStatusDescriptorUser)

        val supportedSpeedDescriptorUser =
            BluetoothGattDescriptor(
                FitnessProtocolConstant.Descriptor_USER,
                BluetoothGattDescriptor.PERMISSION_READ
            )
        mSupportedSpeedRangeCharacteristic = BluetoothGattCharacteristic(
            FitnessProtocolConstant.SupportedSpeedRange,
            BluetoothGattCharacteristic.PROPERTY_READ,
            BluetoothGattCharacteristic.PERMISSION_READ
        )
        mSupportedSpeedRangeCharacteristic.addDescriptor(supportedSpeedDescriptorUser)

        val supportedInclinationRangeDescriptorUser =
            BluetoothGattDescriptor(
                FitnessProtocolConstant.Descriptor_USER,
                BluetoothGattDescriptor.PERMISSION_READ
            )
        mSupportedInclinationRangeCharacteristic = BluetoothGattCharacteristic(
            FitnessProtocolConstant.SupportedInclinationRange,
            BluetoothGattCharacteristic.PROPERTY_READ,
            BluetoothGattCharacteristic.PERMISSION_READ
        )
        mSupportedInclinationRangeCharacteristic.addDescriptor(
            supportedInclinationRangeDescriptorUser
        )

        val supportedResistanceLevelRangeDescriptorUser =
            BluetoothGattDescriptor(
                FitnessProtocolConstant.Descriptor_USER,
                BluetoothGattDescriptor.PERMISSION_READ
            )
        mSupportedResistanceLevelRangeCharacteristic = BluetoothGattCharacteristic(
            FitnessProtocolConstant.SupportedResistanceLevelRange,
            BluetoothGattCharacteristic.PROPERTY_READ,
            BluetoothGattCharacteristic.PERMISSION_READ
        )
        mSupportedResistanceLevelRangeCharacteristic.addDescriptor(
            supportedResistanceLevelRangeDescriptorUser
        )

        val supportedHeartRateRangeDescriptorUser =
            BluetoothGattDescriptor(
                FitnessProtocolConstant.Descriptor_USER,
                BluetoothGattDescriptor.PERMISSION_READ
            )
        mSupportedHeartRateRangeCharacteristic = BluetoothGattCharacteristic(
            FitnessProtocolConstant.SupportedHeartRateRange,
            BluetoothGattCharacteristic.PROPERTY_READ,
            BluetoothGattCharacteristic.PERMISSION_READ
        )
        mSupportedHeartRateRangeCharacteristic.addDescriptor(supportedHeartRateRangeDescriptorUser)

        val supportedPowerRangeDescriptorUser =
            BluetoothGattDescriptor(
                FitnessProtocolConstant.Descriptor_USER,
                BluetoothGattDescriptor.PERMISSION_READ
            )
        mSupportedPowerRangeCharacteristic = BluetoothGattCharacteristic(
            FitnessProtocolConstant.SupportedPowerRange,
            BluetoothGattCharacteristic.PROPERTY_READ,
            BluetoothGattCharacteristic.PERMISSION_READ
        )
        mSupportedPowerRangeCharacteristic.addDescriptor(supportedPowerRangeDescriptorUser)

        val fitnessMachineControlPointDescriptor =
            BluetoothGattDescriptor(
                FitnessProtocolConstant.Descriptor,
                BluetoothGattDescriptor.PERMISSION_WRITE
            )
        val fitnessMachineControlPointDescriptorUser =
            BluetoothGattDescriptor(
                FitnessProtocolConstant.Descriptor_USER,
                BluetoothGattDescriptor.PERMISSION_WRITE
            )
        mFitnessMachineControlPointCharacteristic = BluetoothGattCharacteristic(
            FitnessProtocolConstant.FitnessMachineControlPoint,
            BluetoothGattCharacteristic.PROPERTY_WRITE or BluetoothGattCharacteristic.PROPERTY_INDICATE,
            BluetoothGattCharacteristic.PERMISSION_WRITE
        )
        mFitnessMachineControlPointCharacteristic.addDescriptor(fitnessMachineControlPointDescriptor)
        mFitnessMachineControlPointCharacteristic.addDescriptor(
            fitnessMachineControlPointDescriptorUser
        )

        val fitnessMachineStatusDescriptor =
            BluetoothGattDescriptor(
                FitnessProtocolConstant.Descriptor,
                BluetoothGattDescriptor.PERMISSION_WRITE
            )
        val fitnessMachineStatusDescriptorUser =
            BluetoothGattDescriptor(
                FitnessProtocolConstant.Descriptor_USER,
                BluetoothGattDescriptor.PERMISSION_WRITE
            )
        mFitnessMachineStatusCharacteristic = BluetoothGattCharacteristic(
            FitnessProtocolConstant.FitnessMachineStatus,
            BluetoothGattCharacteristic.PROPERTY_NOTIFY,
            BluetoothGattCharacteristic.PERMISSION_WRITE
        )
        mFitnessMachineStatusCharacteristic.addDescriptor(fitnessMachineStatusDescriptor)
        mFitnessMachineStatusCharacteristic.addDescriptor(fitnessMachineStatusDescriptorUser)

        val fitnessExtendedDescriptorUser =
            BluetoothGattDescriptor(
                FitnessProtocolConstant.Descriptor_USER,
                BluetoothGattDescriptor.PERMISSION_WRITE
            )
        mFitnessExtendedCharacteristic = BluetoothGattCharacteristic(
            FitnessExtendedProtocolConstant.fitnessExtended,
            BluetoothGattCharacteristic.PROPERTY_WRITE,
            BluetoothGattCharacteristic.PERMISSION_WRITE
        )
        mFitnessExtendedCharacteristic.addDescriptor(fitnessExtendedDescriptorUser)

        mFitnessService =
            BluetoothGattService(
                FitnessProtocolConstant.FitnessMachineService,
                BluetoothGattService.SERVICE_TYPE_PRIMARY
            )
        mFitnessService.addCharacteristic(mFitnessMachineFeatureCharacteristic)
        mFitnessService.addCharacteristic(mTrainingStatusCharacteristic)
        mFitnessService.addCharacteristic(mSupportedResistanceLevelRangeCharacteristic)
        mFitnessService.addCharacteristic(mSupportedPowerRangeCharacteristic)
        mFitnessService.addCharacteristic(mFitnessMachineControlPointCharacteristic)
        mFitnessService.addCharacteristic(mFitnessMachineStatusCharacteristic)
        mFitnessService.addCharacteristic(mFitnessExtendedCharacteristic)
        if (this.deviceType == DeviceConstant.treadmill) {
            mFitnessService.addCharacteristic(mSupportedInclinationRangeCharacteristic)
        }
        if (this.deviceType == DeviceConstant.treadmill || this.deviceType == DeviceConstant.indoorBike) {
            mFitnessService.addCharacteristic(mSupportedSpeedRangeCharacteristic)
        }
        if (deviceType == DeviceConstant.treadmill
            || this.deviceType == DeviceConstant.indoorBike
            || this.deviceType == DeviceConstant.crossTrainer
        ) {
            mFitnessService.addCharacteristic(mSupportedHeartRateRangeCharacteristic)
        }
        when (deviceType) {
            DeviceConstant.treadmill -> {
                mFitnessService.addCharacteristic(mTreadmillDataCharacteristic)
            }

            DeviceConstant.indoorBike -> {
                mFitnessService.addCharacteristic(mIndoorBikeDataCharacteristic)
            }

            DeviceConstant.crossTrainer -> {
                mFitnessService.addCharacteristic(mCrossTrainerDataCharacteristic)
            }

            DeviceConstant.rower -> {
                mFitnessService.addCharacteristic(mRowerDataCharacteristic)
            }
        }
    }

    private fun createDisService() {
        mSystemIDCharacteristic = BluetoothGattCharacteristic(
            DisProtocolConstant.systemID,
            BluetoothGattCharacteristic.PROPERTY_READ,
            BluetoothGattCharacteristic.PERMISSION_READ
        )
//        mSystemIDCharacteristic.value = "freak_0780110050540000".toByteArray(Charsets.UTF_8)

        mModelNumberCharacteristic = BluetoothGattCharacteristic(
            DisProtocolConstant.modelNumber,
            BluetoothGattCharacteristic.PROPERTY_READ,
            BluetoothGattCharacteristic.PERMISSION_READ
        )
//        mModelNumberCharacteristic.value = "freak_Treadmill".toByteArray(Charsets.UTF_8)

        mSerialNumberCharacteristic = BluetoothGattCharacteristic(
            DisProtocolConstant.serialNumber,
            BluetoothGattCharacteristic.PROPERTY_READ,
            BluetoothGattCharacteristic.PERMISSION_READ
        )
//        mSerialNumberCharacteristic.value = "freak_54504c000016".toByteArray(Charsets.UTF_8)

        mFirmwareRevisionCharacteristic = BluetoothGattCharacteristic(
            DisProtocolConstant.firmwareRevision,
            BluetoothGattCharacteristic.PROPERTY_READ,
            BluetoothGattCharacteristic.PERMISSION_READ
        )
//        mFirmwareRevisionCharacteristic.value = "freak_V1.0.0".toByteArray(Charsets.UTF_8)

        mHardwareRevisionCharacteristic = BluetoothGattCharacteristic(
            DisProtocolConstant.hardwareRevision,
            BluetoothGattCharacteristic.PROPERTY_READ,
            BluetoothGattCharacteristic.PERMISSION_READ
        )
//        mHardwareRevisionCharacteristic.value = "freak_V1.0.0".toByteArray(Charsets.UTF_8)

        mSoftwareRevisionCharacteristic = BluetoothGattCharacteristic(
            DisProtocolConstant.softwareRevision,
            BluetoothGattCharacteristic.PROPERTY_READ,
            BluetoothGattCharacteristic.PERMISSION_READ
        )
//        mSoftwareRevisionCharacteristic.value = "freak_0780110050540000".toByteArray(Charsets.UTF_8)

        mManufacturerNameCharacteristic = BluetoothGattCharacteristic(
            DisProtocolConstant.manufacturerName,
            BluetoothGattCharacteristic.PROPERTY_READ,
            BluetoothGattCharacteristic.PERMISSION_READ
        )
//        mSoftwareRevisionCharacteristic.value = "freak".toByteArray(Charsets.UTF_8)

        mDisService =
            BluetoothGattService(
                DisProtocolConstant.DeviceInformationService,
                BluetoothGattService.SERVICE_TYPE_PRIMARY
            )
        mDisService.addCharacteristic(mModelNumberCharacteristic)
        mDisService.addCharacteristic(mSerialNumberCharacteristic)
        mDisService.addCharacteristic(mFirmwareRevisionCharacteristic)
        mDisService.addCharacteristic(mHardwareRevisionCharacteristic)
        mDisService.addCharacteristic(mSoftwareRevisionCharacteristic)
        mDisService.addCharacteristic(mManufacturerNameCharacteristic)
        mDisService.addCharacteristic(mSystemIDCharacteristic)
    }

    /**
     *
     */
    private fun openGattServer() {
        LogUtil.i(TAG, "openGattServer")
        mServer = mBluetoothManager!!.openGattServer(this, mBluetoothGattServerCallback)
        displayInfo("初始化BluetoothGattServer成功")
        mLinkedList = LinkedList<BluetoothGattService>()
        mLinkedList.add(mDisService)
        mLinkedList.add(mFitnessService)
        mBlueMessageQueueHandler.sendEmptyMessage(ADD_SERVICE)
    }

    private fun notifyControlSuccess(
        device: BluetoothDevice,
        bluetoothGattCharacteristic: BluetoothGattCharacteristic,
        opCode: Int
    ) {
        mBlueMessageQueue.addNotifyMessage(
            byteArrayOf(
                128.toByte(),
                opCode.toByte(), 1
            ), device, bluetoothGattCharacteristic
        )
    }

    private fun notifyControlUnSupport(
        device: BluetoothDevice,
        bluetoothGattCharacteristic: BluetoothGattCharacteristic,
        opCode: Int
    ) {
        mBlueMessageQueue.addNotifyMessage(
            byteArrayOf(
                128.toByte(),
                opCode.toByte(), 2
            ), device, bluetoothGattCharacteristic
        )
    }

    private fun notifyControlParameterError(
        device: BluetoothDevice,
        bluetoothGattCharacteristic: BluetoothGattCharacteristic,
        opCode: Int
    ) {
        mBlueMessageQueue.addNotifyMessage(
            byteArrayOf(
                128.toByte(),
                opCode.toByte(), 3
            ), device, bluetoothGattCharacteristic
        )
    }

    private fun notifyControlFailed(
        device: BluetoothDevice,
        bluetoothGattCharacteristic: BluetoothGattCharacteristic,
        opCode: Int
    ) {
        mBlueMessageQueue.addNotifyMessage(
            byteArrayOf(
                128.toByte(),
                opCode.toByte(), 4
            ), device, bluetoothGattCharacteristic
        )
    }

    private fun notifyControlUnAllow(
        device: BluetoothDevice,
        bluetoothGattCharacteristic: BluetoothGattCharacteristic,
        opCode: Int
    ) {
        mBlueMessageQueue.addNotifyMessage(
            byteArrayOf(
                128.toByte(),
                opCode.toByte(), 5
            ), device, bluetoothGattCharacteristic
        )
    }

    /**
     * 写数据
     */
    fun notifyMessage(
        device: BluetoothDevice?,
        bluetoothGattCharacteristic: BluetoothGattCharacteristic?,
        data: ByteArray?
    ): Boolean {
        if (device == null) {
            LogUtil.i(TAG, "device is null")
            return false
        }
        if (bluetoothGattCharacteristic == null) {
            LogUtil.i(TAG, "bluetoothGattCharacteristic is null")
            return false
        }
        if (data == null) {
            LogUtil.i(TAG, "data is null")
            return false
        }
        // 设置写操作类型 WRITE_TYPE_DEFAULT，底层会自动分包，不用人为分包
        bluetoothGattCharacteristic.writeType = BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT
        bluetoothGattCharacteristic.value = data
        return mServer.notifyCharacteristicChanged(device, bluetoothGattCharacteristic, false)
    }

    fun sendRespondWithReadOrWrite(
        device: BluetoothDevice?,
        requestId: Int,
        status: Int,
        offset: Int,
        data: ByteArray?
    ) {
        mServer.sendResponse(device, requestId, status, offset, data)
    }
}